package com.example.magical.wichit.magic1;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;
/**
 * ThreadLocal 适用于变量在线程间隔离，而在方法或类间共享的场景,如果用户信息的获取比较昂贵（比如从数据库查询用户信息），那么在 ThreadLocal 中缓存数据是比较合适的做法。
 * 程序运行在 Tomcat 中，执行程序的线程是 Tomcat 的工作线程，而 Tomcat 的工作线程是基于线程池的。也就是说，线程池会重用固定的几个线程，一旦线程重用，
 * 那么很可能首次从 ThreadLocal 获取的值是之前其他用户的请求遗留的值。这时，ThreadLocal 中的用户信息就是其他用户的信息。
 * 所以使用类似 ThreadLocal 工具来存放一些数据时，需要特别注意在代码运行完后，显式地去清空设置的数据。
 */
@RestController
@RequestMapping("threadlocal")
public class ThreadLocalController {

    private static final ThreadLocal<Integer> CURRENT_USER = ThreadLocal.withInitial(() -> null);

    @GetMapping("wrong")
    public Map<String, String> wrong(@RequestParam("userId") Integer userId) {
        String before  = Thread.currentThread().getName() + ":" + CURRENT_USER.get();
        CURRENT_USER.set(userId);
        String after  = Thread.currentThread().getName() + ":" + CURRENT_USER.get();
        Map<String, String> result = new HashMap<>();
        result.put("before", before);
        result.put("after", after);
        return result;
    }

    @GetMapping("right")
    public Map<String, String> right(@RequestParam("userId") Integer userId) {
        String before  = Thread.currentThread().getName() + ":" + CURRENT_USER.get();
        CURRENT_USER.set(userId);
        try {
            String after = Thread.currentThread().getName() + ":" + CURRENT_USER.get();
            Map<String, String> result = new HashMap<>();
            result.put("before", before);
            result.put("after", after);
            return result;
        } finally {
            CURRENT_USER.remove();
        }
    }
}
